home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 011 / bufprn.arc / BUFPRN.ASM next >
Encoding:
Assembly Source File  |  1985-12-05  |  10.9 KB  |  435 lines

  1. name    bufptr
  2. title    Buffered Printer Driver for MSDOS 3.X
  3. subttl    Equates
  4. page 60,132
  5. ;
  6. comment ~
  7. Placed in the public domain by
  8.     Clayton Haapala
  9.     Lee Data Corporation
  10.     Eden Prairie, MN 55344
  11.     (612)828-0460
  12.     December 5, 1985
  13. Non-commercial use only, please!
  14.  
  15. This device driver replaces the drivers for PRN and LPT1, and creates 
  16. the alternate name BPTR. This driver gives you a 16k buffer for 
  17. printing, which is drained by the parallel printer interrupts, IRQ7.  I 
  18. have also added IOCTL support for the DOS 3.X Output Till Busy call, 
  19. but I'm not sure that it works well, since one needs a PRINT program 
  20. that will make use of it, which I don't have yet. There is also 
  21. another IOCTL call to flush that printer buffer; currently, this is the 
  22. only private IOCTL command supported.  The PFLUSH.C program make this
  23. call.  I think this program is a fairly reasonable example of a 
  24. character device driver for MSDOS and I hope you find it usable and 
  25. informative.
  26.  
  27. Caveats:  BUFPRN does not catch any interrupt 17H calls, such has BASIC 
  28. makes when initializing LPT1.  BASIC will cause the parallel port to be 
  29. re-initialized, turning off interrupts on the chip.  Upon the next time 
  30. you use the driver from DOS, then, you may get an Abort, Retry, or 
  31. Ignore message.  Just say "Retry" and you'll hear the printer 
  32. re-initialize again and continue to print.
  33.  
  34. Original IBM-PCs had an error in the motherboard logic that did not 
  35. allow IRQ7 to be honored, even though all chips and ports were enabled. 
  36. The IBM XT works fine, however, as do many compatibles.
  37. ~
  38. ;
  39. ; Added Output Till Busy handling.  Error checking becomes a little more 
  40. ; obscure.  If no room can be found in the buffer within OTB_retries 
  41. ; times through the driver, then report an error, instead of doing a direct 
  42. ; time-out loop.
  43.  
  44. req_hdr        struc
  45.  rlen        db    ?
  46.         db    ?
  47.  rcmd        db    ?
  48.  rstatus    dw    ?
  49.         db    8 dup (?)    ; Reserved
  50.         db    ?
  51.  rtrans        dd    ?
  52.  rcount        dw    ?
  53. req_hdr        ends
  54.  
  55. stat_word    record    ERR:1,RES:5,BSY:1,DUN:1,ERRCD:8
  56.  
  57. bios_data    segment at 40H
  58.         dw 4 dup (?)
  59. printer_base    dw 4 dup (?)
  60. bios_data    ends
  61.  
  62. kelvin        segment at 0
  63.         org    0Fh*4
  64. prn_hvec    label    dword
  65. kelvin        ends
  66.  
  67. OTB_retries    equ    10
  68.  
  69. subttl    Data Declarations
  70. page
  71. code        segment
  72.  
  73.     assume CS:code,DS:nothing,ES:nothing
  74.  
  75. dev_header:
  76.         dd    dev2        ; Pointer to next device
  77.         dw    0E000H        ; Character device, IOCTL, OutTilBusy
  78.         dw    strategy    ; Pointer to strategy routine
  79.         dw    int_entry    ; Pointer to "interrupt" routine
  80.         db    'PRN     '    ; Device name
  81.  
  82. dev2    label    far
  83.         dd    dev3        ; Pointer to next device
  84.         dw    0E000H        ; Character device, IOCTL, OutTilBusy
  85.         dw    strategy    ; Pointer to strategy routine
  86.         dw    int_entry    ; Pointer to "interrupt" routine
  87.         db    'LPT1    '    ; Device name
  88.  
  89. dev3    label    far
  90.         dd    -1        ; Pointer to next device
  91.         dw    0E000H        ; Character device, IOCTL, OutTilBusy
  92.         dw    strategy    ; Pointer to strategy routine
  93.         dw    int_entry    ; Pointer to "interrupt" routine
  94.         db    'BPTR    '    ; Device name
  95.  
  96. req_ptr        dd    0        ; Pointer to request header
  97.  
  98. dispatch    label    word
  99.         dw    init, media, bpb, ioctlin
  100.         dw    input, inkey, instat, inflush
  101.         dw    output, outverf, outstat, outflush
  102.         dw    ioctlout, devopen, devclose, remov_media
  103.         dw    outtilbusy
  104. numcmds        equ    ($ - dispatch) / 2
  105. softint        dw    0        ; True if a soft int to 0F has been done
  106. dev_addr    dw    0        ; Base address of first printer
  107. bufsize        dw    4000h        ; Size of buffer
  108. bufmsk        dw    4000h-1        ; For wrapping pointers
  109. last_err    dw    0        ; Error code from prn_int
  110. count        dw    0        ; Number of bytes in buffer
  111. inpt        dw    0        ; Pointer to next avail free byte
  112. outpt        dw    0        ; Pointer to next char to print
  113. flushed        dw    -1        ; True if interrupt with no data
  114. busyout        db    0        ; True if OutputTilBusy
  115. found_full    db    OTB_retries    ; Error when reaches 0, reset if a
  116.                     ;   byte successfully output
  117. subttl    Procedures
  118. page
  119. strategy    proc    far
  120. ; Store ES:BX in req_ptr
  121.         mov word ptr req_ptr,BX
  122.         mov word ptr req_ptr+2,ES
  123.         ret
  124. strategy    endp
  125.  
  126.     assume    DS:code
  127.  
  128. int_entry    proc    far
  129. ; Called from DOS, this procedure dispatches control to the appropriate
  130. ; routine.  On return to int_done, the done bit is set in the status word.
  131.         push    AX
  132.         push    BX
  133.         push    CX
  134.         push    DX
  135.         push    SI
  136.         push    DI
  137.         push    DS
  138.         push    ES
  139.  
  140.         push    CS
  141.         pop    DS
  142.         les    SI,req_ptr
  143.         mov    BL,ES:[SI].rcmd
  144.         cmp    BL,numcmds        ; Command within range?
  145.         jbe    int_ok            ; Fine
  146.         mov    ES:[SI].rstatus,8003H    ; Unknown command
  147.         jmp short int_done
  148. int_ok:
  149.         xor    BH,BH
  150.         shl    BX,1            ; Make word offset
  151.         jmp    dispatch[BX]        ; Go do it
  152. int_done:
  153.         les    SI,req_ptr
  154.         or    ES:[SI].rstatus,mask DUN
  155.         pop    ES
  156.         pop    DS
  157.         pop    DI
  158.         pop    SI
  159.         pop    DX
  160.         pop    CX
  161.         pop    BX
  162.         pop    AX
  163.         ret
  164. int_entry    endp
  165.  
  166. ; Unsupported command routines:
  167. media:
  168. bpb:
  169. ioctlin:
  170. input:
  171. inkey:
  172. instat:
  173. inflush:
  174. devopen:
  175. devclose:
  176. remov_media:
  177.         mov    ES:[SI].rstatus,8003h    ; Bad command
  178.         jmp    int_done
  179.  
  180. ioctlout:
  181. ; ES:SI points to request header
  182. ; First byte must be an escape, the next must be one of the following:
  183. ;    0FFH     -- flush buffer
  184.         les    SI,ES:[SI].rtrans        ; Where the bytes are
  185.         mov    AX,ES:[SI]                ; Get first two bytes, only
  186.         cmp    AX,0FF1Bh                ; ESC - FF?
  187.         je    outflush                ; Flush the buffer and leave
  188.         jmp    int_done                ; Ignore anything else
  189.  
  190. outstat:
  191. ; Return last_err if non-zero, else return busy if buffer is full
  192.         xor    AX,AX
  193.         xchg    AX,last_err
  194.         or    AX,AX            ; Non-zero?
  195.         jz    outs10            ; No
  196.         or    AH,80H            ; Turn error bit on
  197.         mov    ES:[SI].rstatus,AX
  198.         jmp    int_done
  199. outs10:
  200.         mov    AX,count
  201.         cmp    AX,bufsize        ; Buffer full?
  202.         jb    outs20            ; No
  203.         mov    ES:[SI].rstatus,mask BSY
  204. outs20:
  205.         jmp    int_done
  206.  
  207. outflush:
  208. ; Flush the output buffer
  209.         xor    AX,AX
  210.         mov    count,AX
  211.         mov    inpt,AX
  212.         mov    outpt,AX
  213.         mov    last_err,AX
  214.         jmp    int_done
  215.  
  216. outtilbusy:
  217.         mov    busyout,1        ; Make True
  218. outverf:
  219. output:
  220. ; Output chars to the buffer. A time-out check is performed for each char,
  221. ; so it is an error if no space in the buffer opens up in time.  All chars
  222. ; are output until no more or last_err goes non-zero.
  223. ; COUNT is the number of chars in the buffer.
  224. ; INPT points to the next place to add a char.
  225.  
  226. ; First check to see that the printer has not been "uninitialized", that is,
  227. ; see that interrupts have not been turned off.
  228.         mov    DX,dev_addr
  229.         add    DX,2
  230.         in    AL,DX            ; Get current init parms
  231.         test    AL,10h            ; Interrupts enabled?
  232.         jnz    out5            ; Yes, no problem
  233. ; Re-initialize, should happen only once at first output...
  234.         mov    AL,8            ; Select printer
  235.         out    DX,AL
  236.         mov    AX,2000
  237. out2:        dec    AX
  238.         jnz    out2            ; Delay
  239.         mov    AL,1Ch            ; Ints on, init high, no ALF
  240.         out    DX,AL
  241. out5:
  242.         mov    CX,ES:[SI].rcount    ; How many to output
  243.         les    SI,ES:[SI].rtrans    ; Where the chars are
  244. out10:
  245.         mov    AL,ES:[SI]        ; Get a char
  246.         inc    SI
  247. out15:
  248.         mov    BL,10            ; Set up for time-out
  249. out20:
  250.         xor    DX,DX
  251. out30:
  252.         cmp    last_err,0        ; Any hard error?
  253.         jnz    out34            ; Yes
  254.         mov    DI,count
  255.         cmp    DI,bufsize        ; Any room?
  256.         jb    out40            ; Yes
  257. ;
  258. ; If we are Outputting Until Busy, check if we have found no room for
  259. ; OTB_retries times.  Error if so, return actual output if not.
  260.         cmp    busyout,0        ; Output Til Busy?
  261.         jz    out32            ; No
  262.         dec    found_full        ; Been full too often?
  263.         jz    out34            ; Yes, report error
  264.         sub    ES:[SI].rcount,CX    ; Report bytes output
  265.         jmp    int_done        ; Outputted until busy...
  266. out32:
  267. ; Decrement loop counter -- we'll wait a while for some room, since we're
  268. ; not Outputting until Busy like above.
  269.         dec    DX
  270.         jnz    out30
  271.         dec    BL
  272.         jnz    out20
  273.         mov    softint,-1        ; Check the status
  274.         int    0Fh            ; What's going on?
  275.         cmp    last_err,0        ; Anything? Maybe jump start...
  276.         jz    out15            ; Try again
  277. out34:
  278.         les    SI,req_ptr
  279.         mov    AX,last_err
  280.         or    AH,80h            ; Set error bit
  281.         mov    ES:[SI].rstatus,AX
  282.         sub    ES:[SI].rcount,CX    ; # of bytes output
  283.         mov    last_err,0        ; Zero out for next time
  284.         jmp    int_done
  285. out40:
  286. ; Output a byte to the buffer, start printing if necessary.  Reset found_full
  287. ; to OTB_retries to show that all is OK.
  288.  
  289.         mov    found_full,OTB_retries    ; Reset error count
  290.         cli
  291.         mov    DI,inpt
  292.         mov    buffer[DI],AL    ; Store char
  293.         inc    count            ; Update
  294.         inc    DI
  295.         and    DI,bufmsk        ; Wrap, maybe
  296.         mov    inpt,DI            ; Restore pointer
  297.         sti
  298.         xor    AX,AX
  299.         xchg    AX,flushed
  300.         or    AX,AX            ; Need to jump start?
  301.         jz    out50            ; No
  302.         mov    softint,-1        ; Say "no EOI"
  303.         int    0Fh            ; Start things going...
  304. out50:
  305.         loop    o_again            ; Do it for the next char
  306. ; Everything output without a hitch...the rcount IS the number of bytes
  307. ; output.
  308.         jmp    int_done
  309. o_again:                    ; One more time (at least)
  310.         jmp    out10
  311.  
  312.     assume    DS:code
  313.  
  314. prn_int        proc    far
  315. ; Hard interrupt handler for vector 0Fh.  Check the status and then pull
  316. ; a byte from the buffer if all is well.  If bad status then set last_err
  317. ; to the proper error code.   If the buffer is empty, set flushed to TRUE
  318. ; so the next output will start the interrupts going again.  If the variable
  319. ; SOFTINT is true, don't perform an EOI at the end, because the driver has
  320. ; initiated this interrupt, not the hardware.
  321.  
  322.         sti
  323.         push    AX
  324.         push    DX
  325.         push    SI
  326.         push    DS
  327.  
  328.         push    CS
  329.         pop    DS
  330.  
  331. ; Check for bad status
  332.         mov    DX,dev_addr
  333.         inc    DX            ; Get status port
  334.         in    AL,DX            ; Read status
  335.         xor    AL,48h            ; Flip a couple bits
  336.         test    AL,28h            ; Any errors?
  337.         jz    pok            ; Ok to print
  338.         mov    SI,9
  339.         test    AL,20h            ; Paper out?
  340.         jnz    p10            ; Yes
  341.         mov    SI,2            ; Say "device not ready"
  342. p10:
  343.         mov    last_err,SI        ; Store error code
  344.         jmp short p99
  345. pok:
  346. ; Get char from the buffer
  347.         cmp    count,0
  348.         jnz    p20            ; Buffer not empty
  349.         mov    flushed,-1
  350.         jmp short p99
  351. p20:
  352.         mov    SI,outpt
  353.         mov    AL,buffer[SI]        ; Get char
  354.         dec    count            ; Update counter and
  355.         inc    SI            ;   pointer
  356.         and    SI,bufmsk
  357.         mov    outpt,SI
  358.  
  359. ; Output the character and strobe the printer
  360.  
  361.         dec    DX            ; Data port
  362.         out    DX,AL            ; Output the byte
  363.         add    DX,2            ; Strobe port
  364.         in    AL,DX
  365.         or    AL,1            ; Set strobe bit high
  366.         out    DX,AL
  367.         and    AL,0FEh            ; Set strobe bit low
  368.         out    DX,AL
  369. p99:
  370. ; Exit interrupt handler
  371.         xor    AX,AX
  372.         xchg    AX,softint
  373.         or    AX,AX            ; A soft interrupt?
  374.         cli
  375.         jnz    p100            ; Yes, no EOI
  376.         mov    AL,20h
  377.         out    20h,AL            ; Do EOI
  378. p100:
  379.         pop    DS
  380.         pop    SI
  381.         pop    DX
  382.         pop    AX
  383.         iret
  384. prn_int        endp
  385.  
  386. buffer        label    byte
  387. been_here    db    0
  388.  
  389. init:
  390. ; Perform device initialization
  391.         push    DS
  392.  
  393.     assume DS:kelvin
  394.  
  395.         cmp been_here,1
  396.         je    fnd_end            ; Don't re-init
  397.  
  398.         xor    AX,AX
  399.         mov    DS,AX
  400.         mov word ptr prn_hvec,offset prn_int
  401.         mov word ptr prn_hvec+2,CS
  402.         mov    AX,40h
  403.         mov    DS,AX
  404.  
  405.     assume DS:bios_data
  406.  
  407.         mov    DX,printer_base        ; Address of first printer
  408.         mov    dev_addr,DX        ; Store locally
  409.         add    DX,2
  410.         mov    AL,8            ; Select printer
  411.         out    DX,AL
  412.         mov    AX,2000
  413. init10:        dec    AX
  414.         jnz    init10            ; Delay
  415.         mov    AL,1Ch            ; Ints on, init high, no ALF
  416.         out    DX,AL
  417.  
  418.     assume DS:code
  419.  
  420. fnd_end:
  421.         pop    DS
  422.         mov    AX,bufsize
  423.         add    AX,offset buffer
  424.         inc    AX            ; End of driver addres + 1
  425.         mov    ES:[SI+14],AX        ; Offset of end of driver
  426.         mov    ES:[SI+16],CS        ; Segment of end of driver
  427.         in    AL,21h            ; Get interrupt mask
  428.         and    AL,7Fh            ; Enable IRQ7
  429.         out    21h,AL
  430.         jmp    int_done
  431.  
  432. code        ends
  433. ;
  434.         end
  435.